#ifndef __THREAD_H_
#define __THREAD_H_

#include <memory>
#include <functional>
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <sys/syscall.h>
#include <semaphore.h>

namespace learnco {

//信号量，调度线程，站在线程视角(mutex站在资源视角)
class Semaphore {
public:
    Semaphore(uint32_t count=0);
    ~Semaphore();
private:
    Semaphore(const Semaphore&) = delete;
    Semaphore(const Semaphore&&) = delete;
    Semaphore& operator=(const Semaphore&) = delete;

private:
    sem_t m_semaphore;

public:
    void wait();
    void notify();
};

//互斥器RAII封装器
template<class T>
class RaiiLockImpl {
private:
    T& m_mutex;
    bool m_loacked;

public:
    RaiiLockImpl(T& mutex)
        :m_mutex(mutex) {
        m_mutex.lock();
        m_loacked = true;
    }

    ~RaiiLockImpl() {
        m_mutex.unlock();
    }

    void lock(){
        if(!m_loacked){
            m_mutex.lock();
            m_loacked=true;
        }
    }

    void unlock(){
        if(m_loacked){
            m_mutex.unlock();
            m_loacked=false;
        }
    }
};

//互斥器
class Mutex {
public:
    typedef RaiiLockImpl<Mutex> RaiiImpl;
private:
    pthread_mutex_t m_mutex;
public:
    Mutex()         { pthread_mutex_init(&m_mutex, nullptr);} 
    ~Mutex()        { pthread_mutex_destroy(&m_mutex);} 
public:
    void lock()     {pthread_mutex_lock(&m_mutex);}
    void unlock()   {pthread_mutex_unlock(&m_mutex);}
};

//RAII 封装读
template<class T>
class readRaiiLockImpl {

private:
    T& m_mutex;
    bool m_loacked;

public:
    readRaiiLockImpl(T& mutex)
        :m_mutex(mutex) {
        m_mutex.rdlock();
        m_loacked = true;
    }

    ~readRaiiLockImpl() {
        if(m_loacked){
            m_loacked = false;
            m_mutex.unlock();
        }
    }

    void lock(){
        if(!m_loacked){
            m_mutex.rdlock();
            m_loacked = true;
        }
    }

    void unlock(){
        if(m_loacked){
            m_loacked = false;
            m_mutex.unlock();
        }
    }
};

//RAII 封装写
template<class T>
class writeRaiiLockImpl {
private:
    T& m_mutex;
    bool m_loacked;

public:
    writeRaiiLockImpl(T& mutex)
        :m_mutex(mutex) {
        m_mutex.wrlock();
        m_loacked = true;
    }

    ~writeRaiiLockImpl() {
        if(m_loacked){
            m_loacked = false;
            m_mutex.unlock();
        }
    }

    void lock(){
        if(!m_loacked){
            m_mutex.wrlock();
            m_loacked = true;
        }
    }

    void unlock(){
        if(m_loacked){
            m_loacked = false;
            m_mutex.unlock();
        }
    }
};


//读写锁：适合于对数据结构读的次数远大于写的情况
class RWMutex {
public:
    typedef readRaiiLockImpl<RWMutex> readRaiiImpl;
    typedef writeRaiiLockImpl<RWMutex> writeRaiiImpl;
private:
    pthread_rwlock_t m_rwlock;
public:
    RWMutex()         { pthread_rwlock_init(&m_rwlock, nullptr);} 
    ~RWMutex()        { pthread_rwlock_destroy(&m_rwlock);} 
public:
    void rdlock()     {pthread_rwlock_rdlock(&m_rwlock);}
    void wrlock()     {pthread_rwlock_wrlock(&m_rwlock);}
    void unlock()     {pthread_rwlock_unlock(&m_rwlock);}
};



class Thread {
public:
    typedef std::shared_ptr<Thread> ptr;
    Thread(std::function<void()> cb, const std::string& name = "UNKOWN");
    ~Thread();

private:
    Thread() =delete;
    Thread(const Thread&) = delete;
    Thread(const Thread&&) = delete;
    Thread& operator=(const Thread&) = delete;

private:
    pid_t m_id = -1;
    pthread_t m_thread = 0;
    std::function<void()> m_cb;
    std::string m_name;
    Semaphore m_semaphore;

public:
    pid_t getId() const { return m_id;}
    const std::string& getName() const { return m_name;}

    static Thread* GetThis();
    static void SetName(const std::string& name);
    static const std::string& GetName();
    static void* run(void* arg);

    void join();
};

}




#endif